﻿using FanaticRock.Core.DI;
using FanaticRock.Core.ServiceInterfaces;
using System;
using System.Linq.Expressions;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace FanaticRock.Database.LiteDb
{
    [InjectMe(typeof(ILocalDbService))]
    public class LiteDbService : ILocalDbService
    {
        private string _connectString = @"Filename=xxx";
        private bool _isChanged;

        public LiteDbService()
        {
            var dirPath = AppDomain.CurrentDomain.BaseDirectory;
            var dbPath = Path.Combine(dirPath, "data.db");
            _connectString = $"Filename={dbPath}";
            _isChanged = false;
        }

        public bool IsChanged()
        {
            return _isChanged;
        }

        public void SetChanged()
        {
            _isChanged = true;
        }

        public void Flush()
        {

        }

        public void Init()
        {

        }


        public async Task<T> UpsertAsync<T>(T obj)
        {
            _isChanged = true;
            using var db = new LiteDB.LiteDatabase(_connectString);
            var coll = db.GetCollection<T>();
            coll.Upsert(obj);
            return obj;
        }

        public async Task UpsertAsync<T>(IEnumerable<T> obj)
        {
            _isChanged = true;
            using var db = new LiteDB.LiteDatabase(_connectString);
            var coll = db.GetCollection<T>();
            foreach (var item in obj)
            {
                coll.Upsert(item);
            }

        }

        public async Task<T> GetByIdAsync<T>(string id)
        {
            using var db = new LiteDB.LiteDatabase(_connectString);
            var coll = db.GetCollection<T>();
            return coll.FindById(id);
        }

        public async Task<IEnumerable<T>> Where<T>(Expression<Func<T, bool>> predicate)
        {
            using var db = new LiteDB.LiteDatabase(_connectString);
            var coll = db.GetCollection<T>();

            var result = coll.Query().Where(predicate).ToArray();
            return result;
        }

        public async Task<T> FirstOrDefault<T>(Expression<Func<T, bool>> predicate)
        {
            using var db = new LiteDB.LiteDatabase(_connectString);
            var coll = db.GetCollection<T>();

            var result = coll.FindOne(predicate);
            return result;
        }

        public async Task<IEnumerable<T>> Query<T>()
        {
            using var db = new LiteDB.LiteDatabase(_connectString);
            var coll = db.GetCollection<T>();

            var result = coll.Query().ToEnumerable().ToArray();

            return result;
        }


        public async Task Query<T>(Action<IEnumerable<T>> action)
        {
            using var db = new LiteDB.LiteDatabase(_connectString);
            var coll = db.GetCollection<T>();

            var result = coll.Query().ToEnumerable();
            action?.Invoke(result);
        }

        public async Task Clear<T>()
        {
            _isChanged = true;
            using var db = new LiteDB.LiteDatabase(_connectString);
            var coll = db.GetCollection<T>();
            coll.DeleteAll();
        }
    }
}
